﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Globalization;

namespace BuddHa.Common.DateTimeOpex
{
    public class DateTimeHelper
    {
        private static DateTime _doomsDay;
        private static DateTime _futureDay;

        /// <summary>
        /// 末日时间
        /// </summary>
        public static DateTime DoomsDay
        {
            get
            {
                if (_doomsDay == default || _doomsDay.Ticks == 0)
                {
                    _doomsDay = new DateTime(1970, 1, 1);
                }
                return _doomsDay;
            }
        }

        /// <summary>
        /// 未来时间（2099年）
        /// </summary>
        public static DateTime FutureDay
        {
            get
            {
                if (_futureDay == default || _futureDay.Ticks == 0)
                {
                    _futureDay = new DateTime(2099, 1, 1);
                }
                return _futureDay;
            }
        }

        /// <summary>
        /// 日期相隔天数
        /// </summary>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        /// <returns></returns>
        public static int periodDays(string startTime, string endTime, string format)
        {
            var dateStartTime = DateTime.ParseExact(startTime, format, System.Globalization.CultureInfo.CurrentCulture);
            var dateEndTime = DateTime.ParseExact(endTime, format, System.Globalization.CultureInfo.CurrentCulture);
            var ts = dateEndTime - dateStartTime;
            return ts.Days;
        }

        /// <summary>
        /// 获得今天是当年的第几天
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public static int GetYearTotalDays(DateTime dateTime)
        {
            var begindate = new DateTime(dateTime.Year - 1, 12, 31);
            var diff = dateTime - begindate;
            return Convert.ToInt32(diff.TotalDays);
        }

        /// <summary>
        /// 根据日期获得星期几
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public static string GetCNDayOfWeek(DateTime dateTime)
        {
            string[] weekRemarks = new string[] { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
            string week_CN = weekRemarks[Convert.ToInt16(dateTime.DayOfWeek)];//中文星期几
            return week_CN;
        }

        /// <summary>
        /// 获取某个日期，本周第一天
        /// </summary>
        public static DateTime GetWeekOne(DateTime time)
        {
            switch (time.DayOfWeek.ToString())
            {

                case "Monday":
                    {
                        return Convert.ToDateTime(time.AddDays(0).ToLongDateString());
                    }

                case "Tuesday":
                    {
                        return Convert.ToDateTime(time.AddDays(-1).ToLongDateString());
                    }

                case "Wednesday":
                    {
                        return Convert.ToDateTime(time.AddDays(-2).ToLongDateString());
                    }

                case "Thursday":
                    {
                        return Convert.ToDateTime(time.AddDays(-3).ToLongDateString());
                    }

                case "Friday":
                    {
                        return Convert.ToDateTime(time.AddDays(-4).ToLongDateString());
                    }

                case "Saturday":
                    {
                        return Convert.ToDateTime(time.AddDays(-5).ToLongDateString());
                    }

                case "Sunday":
                    {
                        return Convert.ToDateTime(time.AddDays(-6).ToLongDateString());
                    }
            }

            return default;
        }

        /// <summary>
        /// 获取某个日期，本季度第一天
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        public static DateTime GetQuarterlyOne(DateTime time)
        {
            var month = time.Month;

            var startTime = Convert.ToDateTime(time.Year + "-01-01");

            if (month < 4)
            {
                return startTime;
            }
            else if (month > 3 && month < 7)
            {
                return startTime.AddMonths(3);
            }
            else if (month > 6 && month < 10)
            {
                return startTime.AddMonths(6);
            }
            else if (month > 9)
            {
                return startTime.AddMonths(9);
            }

            return default;
        }

        /// <summary>
        /// 获取一个时间是第几季度
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        public static int GetQuarterly(DateTime time)
        {

            var month = time.Month;

            int quarterly = 0;

            if (month <= 3)
            {
                quarterly = 1;
            }
            else if (month >= 4 & month <= 6)
            {
                quarterly = 2;
            }
            else if (month >= 7 & month <= 9)
            {
                quarterly = 3;
            }
            else if (month >= 10 & month <= 12)
            {
                quarterly = 4;
            }

            return quarterly;
        }

        /// <summary>
        /// 获取NTP网络远程时间
        /// </summary>
        /// <returns></returns>
        public static DateTimeOffset GetNetworkTime()
        {

            string ntpServer = "ntp.onekib.com";

            var ntpData = new byte[48];

            ntpData[0] = 0x1B;

            var addresses = Dns.GetHostEntry(ntpServer).AddressList;

            IPEndPoint ipEndPoint = new(addresses[0], 123);
            Socket socket = new(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

            socket.Connect(ipEndPoint);

            socket.ReceiveTimeout = 3000;

            socket.Send(ntpData);
            socket.Receive(ntpData);
            socket.Close();

            const byte serverReplyTime = 40;

            ulong intPart = BitConverter.ToUInt32(ntpData, serverReplyTime);

            ulong fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4);

            intPart = (uint)(((intPart & 0x000000ff) << 24) + ((intPart & 0x0000ff00) << 8) + ((intPart & 0x00ff0000) >> 8) + ((intPart & 0xff000000) >> 24));
            fractPart = (uint)(((fractPart & 0x000000ff) << 24) + ((fractPart & 0x0000ff00) << 8) + ((fractPart & 0x00ff0000) >> 8) + ((fractPart & 0xff000000) >> 24));

            var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);

            var networkDateTime = (new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds((long)milliseconds);

            return networkDateTime;
        }

        /// <summary>
        /// 通过时间格式字符串获取时间
        /// </summary>
        /// <param name="timeText">如：2022.02.02</param>
        /// <param name="format">如：yyyy.MM.dd</param>
        /// <returns></returns>
        public static DateTimeOffset GetTimeByString(string timeText, string format)
        {
            return DateTimeOffset.ParseExact(timeText, format, CultureInfo.CurrentCulture);
        }


    }
}
